home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 19 / Mac Magazin and MacEasy Magazine CD - Issue 19.iso / Musik & Kunst / Ear Workout 2.1 / source code / ear_about_chord.cp < prev    next >
Text File  |  1996-01-15  |  11KB  |  311 lines

  1.  
  2.  
  3. //
  4. // current shortcomings:
  5. //    doesn't know about ledger lines, except for middle C
  6. //    note heads and accidentals don't look so great
  7. //    should allow user to set the value of spell spell_dim7_enharmonically
  8. //        as a matter of preference
  9. //    sometimes leaves notes out of staff:
  10. //         happened for F#m, drew F# and C# only !?!?
  11. //        might have to do with reinterpreting m7 <-> 6
  12. //    on very first chord, draws accidentals but then erases them later
  13. //        when it redraws the chord
  14. //    should try to spell chord so as to avoid double sharps and double-flats,
  15. //        e.g. G# dim7, not Ab dim 7
  16. //    has problems with the ADDMAJ7 item, spells it as 6:
  17. //      screwed up on writing a C#m maj 7 chord voiced as E, G#, Bx, C#(oct up)
  18. //        wrote Bx as A, wrote accidentals in funny places
  19. //      spells Ab b5 maj7 with Fx instead of G
  20. //    should have curly brace at left
  21. //
  22. // fixed (?):
  23. //    if a chord has 2 seconds in a row, should bring the top note back
  24. //        to the left
  25. //    spells 4 of sus 4 as #3
  26. //    chord symbols:
  27. //        should use space in some cases, e.g. "E half-dim", not "Ehalf-dim"
  28. //        should say "G", not "GM"
  29. //    If a note is offset to the right to avoid colliding with one a second
  30. //        below it, and only the higer note has an accidental, don't
  31. //        need to offset the accidental.
  32.  
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <math.h>
  37.  
  38. #include <OSUtils.h>
  39. #include <QuickDraw.h>
  40. #include <Sound.h>
  41.  
  42. #define NEED_MAC_STUFF 1
  43.  
  44. #include "Ninkasi:C++ util:generic.h"
  45. #include "Ninkasi:C++ util:complete_window.h"
  46. #include "ear_defines.h"
  47. #include "ear_decl.h"
  48. #include "ear_prototypes.h"
  49.  
  50. DEN_MOTHER_T about_chord_den_mother;
  51.  
  52. #define MAXPART 200
  53.     // highest part number in our window
  54.  
  55. extern double fabs(),sin(),cos();
  56.  
  57.  
  58.     void
  59. about_chord_den_mother(complete_window *my_complete_window)
  60.     {
  61.       //--- decoder string for controls:
  62.       static char *decoder_ptr =
  63.  
  64. "\0staff,symbol,tx1,chord_no";
  65.         //--- has to begin with null so subroutines know it's not really
  66.         //    a Pascal string
  67.         
  68.       static char **decoder_string = &decoder_ptr;
  69.  
  70.       static int first_time = 1;
  71.       static int ready_to_update,need_to_redraw,need_to_redraw_all;
  72.       static int root_letter,root_accidental;
  73.       
  74.       char nifty_name[300];
  75.       int nifty_index;
  76.  
  77.       GrafPtr save_graf;
  78.  
  79.       
  80.       need_to_redraw = 0;
  81.       need_to_redraw_all = 0;
  82.       ready_to_update = 0;
  83.       
  84.            
  85.       if (first_time) { 
  86.         first_time = 0;
  87.       }
  88.  
  89.  
  90.       switch(my_complete_window->whassup) {
  91.         case complete_window_created:
  92.           need_to_redraw = 1;
  93.           need_to_redraw_all = 1;
  94.           about_chord_window_exists = 1;
  95.           break;
  96.         case complete_window_redraw:
  97.           need_to_redraw = 1;
  98.           need_to_redraw_all = 1;
  99.           ready_to_update = 1; //-- main program does begin update & sets graf port
  100.           break;
  101.         case complete_window_action:
  102.           part_number_to_nifty_label(nifty_name,&nifty_index,
  103.             *decoder_string,my_complete_window->part_number);
  104.           if (nifty_index != -999) {
  105.             if (strcmp(nifty_name,"aardvark")==0) {
  106.             }
  107.           }//--end if they hit a valid control
  108.           break;
  109.         case complete_window_erase:
  110.           first_time = 1;
  111.           return;
  112.       }
  113.  
  114.       if (need_to_redraw) {
  115.         if (!ready_to_update) {
  116.           GetPort(&save_graf);
  117.           SetPort(my_complete_window->the_window);
  118.         }
  119.         if (have_previous_chord) {
  120.           //----- draw staff and chord on it ------
  121.           Rect rr,staff;
  122.           short x_mid,y_mid,x,y,staff_top,staff_bottom,x_chord,y_chord;
  123.           double h;
  124.           Handle hh;
  125.           char s[200],s2[200];
  126.           Point p;
  127.           int list_position_on_staff[MAX_CHORD_NOTES];
  128.           int i,err,note_letter,accidental,
  129.               rough_position_on_staff,position_on_staff,last_position_on_staff,
  130.               last_note_was_offset,last_note_had_accidental,offset,
  131.               last_accidental_was_offset,width_of_note,bar_line_top,
  132.               bar_line_bottom;
  133.           
  134.           get_rect_by_nifty_label(my_complete_window->the_window,
  135.                  "staff",1,decoder_ptr,&rr);
  136.           FillRect(&rr,&white);
  137.             h = 10.; //-- distance between lines on staff
  138.             y_mid = .5*(rr.top+rr.bottom)+.5;
  139.             x_mid = .5*(rr.left+rr.right)+.5;
  140.             staff_top   = y_mid-2*h+.5;
  141.             staff_bottom = y_mid+2*h+.5;
  142.             
  143.             x_chord = x_mid + 1.5 * h;
  144.             y_chord = y_mid;
  145.             
  146.             // treble clef:
  147.             SetRect(&staff,rr.left,staff_top,rr.right,staff_bottom);
  148.             bar_line_top = staff_top;
  149.             draw_staff(&staff);
  150.             draw_clef("draw","g_clef",
  151.                 (int) (x_mid-30),(int) y_mid,h,(void *) 0,(void *) 0);
  152.             
  153.             // bass clef:
  154.             staff_top = staff_top + 6*h;
  155.             staff_bottom = staff_bottom + 6*h;
  156.             SetRect(&staff,rr.left,staff_top,rr.right,staff_bottom);
  157.             bar_line_bottom = staff_bottom;
  158.             draw_staff(&staff);
  159.             draw_clef("draw","f_clef",
  160.                 (int) (x_mid-30),(int) (y_mid+6*h),h,(void *) 0,(void *) 0);
  161.             
  162.             //  double bar:
  163.             MoveTo((short) (rr.right-.5*h),(short) bar_line_top);
  164.             LineTo((short) (rr.right-.5*h),(short) bar_line_bottom);
  165.             MoveTo((short) (rr.right),(short) bar_line_top);
  166.             LineTo((short) (rr.right),(short) bar_line_bottom);
  167.             
  168.             // single bar at left to show it's a grand staff; should
  169.             // also have curly brace
  170.             MoveTo((short) (rr.left),(short) bar_line_top);
  171.             LineTo((short) (rr.left),(short) bar_line_bottom);
  172.             
  173.             sort_int_list(previous_chord,previous_n_notes);
  174.             draw_note_head("set_h",0,0,0,(void *) 0,&h);
  175.             draw_note_head("right_tangent",
  176.                 (int) x_chord,(int) y,0,(void *) &p,(void *) 0);
  177.             width_of_note = 2*(p.h-x_chord);
  178.             
  179.             switch(make_0_to_11(previous_root-MIDDLE_C)) {
  180.               case 0: root_letter = 0; root_accidental = 0; break; // C
  181.               case 1: root_letter = 0; root_accidental = 1; break; // C#
  182.               case 2: root_letter = 1; root_accidental = 0; break; // D
  183.               case 3: root_letter = 2; root_accidental = -1; break; // Eb
  184.               case 4: root_letter = 2; root_accidental = 0; break; // E
  185.               case 5: root_letter = 3; root_accidental = 0; break; // F
  186.               case 6: root_letter = 3; root_accidental = 1; break; // F#
  187.               case 7: root_letter = 4; root_accidental = 0; break; // G
  188.               case 8: root_letter = 5; root_accidental = -1; break; // Ab
  189.               case 9: root_letter = 5; root_accidental = 0; break; // A
  190.               case 10: root_letter = 6; root_accidental = -1; break; // Bb
  191.               case 11: root_letter = 6; root_accidental = -1; break; // B
  192.             }
  193.             last_position_on_staff = -999;
  194.             for (i=0; i<previous_n_notes; i++) {
  195.               spell_note_as_part_of_chord(&err,¬e_letter,&accidental,
  196.                   previous_chord[i]-previous_root,root_letter,root_accidental,
  197.                   previous_item,previous_n_items,spell_dim7_enharmonically);
  198.               if (err==0) {
  199.                 rough_position_on_staff = (previous_chord[i]-(MIDDLE_C+11.))*7./12.;
  200.                   //...relative to B in middle of treble clef
  201.                 position_on_staff = note_letter-6;
  202.                   //...relative to B in middle of treble clef
  203.                 while (position_on_staff<rough_position_on_staff-3.5)
  204.                   position_on_staff += 7;
  205.                 while (position_on_staff>rough_position_on_staff+3.5)
  206.                   position_on_staff -= 7;
  207.                 list_position_on_staff[i] = position_on_staff;
  208.                 y = y_chord-.5*h*position_on_staff;
  209.                 if (position_on_staff<last_position_on_staff+2
  210.                     && !last_note_was_offset) {
  211.                   offset = width_of_note;
  212.                   last_note_was_offset = 1;
  213.                 }
  214.                 else {
  215.                   offset = 0;
  216.                   last_note_was_offset = 0;
  217.                 }
  218.                 x = x_chord+offset;
  219.                 draw_note_head("draw",(int) x,(int) y,0,(void *) 0,(void *) 0);
  220.                 if (position_on_staff == -6) {
  221.                     // ledger line for middle C
  222.                     MoveTo((short) (x-h),(short) y);
  223.                     LineTo((short) (x+h),(short) y);
  224.                 }
  225.                 if (accidental!=0) {
  226.                   char s[100];
  227.                   FontInfo fi;
  228.                   short x_acc,y_acc;
  229.                   describe_accidental(s+1,accidental);
  230.                   s[0] = strlen(s);
  231.                   normal_text_style();
  232.                   GetFontInfo(&fi);
  233.                   x_acc = x_chord-h-5-StringWidth((unsigned char *) s);
  234.                   if (position_on_staff<last_position_on_staff+2
  235.                           && last_note_had_accidental 
  236.                           && !last_accidental_was_offset) {
  237.                     x_acc = x_acc + width_of_note;
  238.                     last_accidental_was_offset = 1;
  239.                   }
  240.                   else
  241.                     last_accidental_was_offset = 0;
  242.                   y_acc = y+.5*fi.ascent;
  243.                   if (accidental<0) y_acc = y_acc-2;
  244.                   if (accidental==2) y_acc = y_acc-1;
  245.                   MoveTo(x_acc,y_acc);
  246.                   DrawString((unsigned char *) s);
  247.                   normal_text_style();
  248.                 } //-- end if accidental
  249.                 last_position_on_staff = position_on_staff;
  250.                 last_note_had_accidental = (accidental!=0);
  251.               } //-- end if no error
  252.             } //-- end loop over notes
  253.  
  254.           //----- chord symbol ------
  255.           {
  256.             char s1[100],s2[30],s3[100];
  257.             Handle hh;
  258.             get_item_by_nifty_label(my_complete_window->the_window,
  259.                   "symbol",1,decoder_ptr,&hh);
  260.             if (VALID_HANDLE(hh)) {
  261.               describe_chord(s3,previous_n_items,previous_item);
  262.               if (strcmp(s3,"M")==0)
  263.                 strcpy(s3,"");
  264.               if (strlen(s3)>=8 && strncmp(s3,"half-dim",8)==0)
  265.                 sprintf(s1," %s",s3);
  266.               else
  267.                 strcpy(s1,s3);
  268.               describe_accidental(s2,root_accidental);
  269.               sprintf(s+1,"%c%s%s",
  270.                   "CDEFGAB"[root_letter],
  271.                   s2,s1);
  272.               s[0] = strlen(s+1);
  273.           normal_text_style();
  274.               SetIText(hh,(unsigned char *) s);
  275.           normal_text_style();
  276.             }
  277.           }
  278.  
  279.           //----- chord number ------
  280.           {
  281.             Handle hh;
  282.             char s[50];
  283.             int chord_no;
  284.             chord_no = nifty_chord_number(previous_chord,previous_n_notes);
  285.             //chord_no = notes_to_quick_label(previous_chord,previous_n_notes);
  286.             sprintf(s+1,"%d",chord_no);
  287.             s[0] = strlen(s+1);
  288.             get_item_by_nifty_label(my_complete_window->the_window,
  289.                   "chord_no",1,decoder_ptr,&hh);
  290.             if (VALID_HANDLE(hh)) {
  291.               normal_text_style();
  292.               SetIText(hh,(unsigned char *) s);
  293.               normal_text_style();
  294.             }
  295.           }
  296.             
  297.         } //-- end if have previous chord
  298.         //----- static text ------
  299.         normal_text_style();
  300.         refresh_text(my_complete_window,"tx1",1,decoder_ptr);
  301.         normal_text_style();
  302.         if (!ready_to_update) {
  303.           SetPort(save_graf);
  304.         }
  305.       }//---end if need to redraw
  306.  
  307.  
  308.  
  309.     }
  310.  
  311.